#ifndef TORUS_H
#define TORUS_H

#include "ring.h"
#include "coord.h"

#include <assert.h>

/*!
 *\brief The Torus struct contain a set of member and method to virtualy structure a contigous range of processor id into a torus. \n
 * It contains methods to naviguate through next and previous columns and row
 */

struct Torus
{
    /*! \brief lenght */
	int lenght;

    /*!
     * \brief operator [] return a `Ring` object the represent the row ring at argument passed rank. \n
     * This operator is designed to access to the processor id directly using this (x,y) coordinate in the torus
     * like presented in the exemple bellow :
     * ~~~~~~~~~~~~~~~{.cpp}
     * //this code obtain the processor id at line 3 column 2 of torus of size 4.
     * int my_processor_id;
     * Torus tor;
     * tor.lenght = 4;
     * my_processor_id = tor[3][2];
     * ~~~~~~~~~~~~~~~
     */
    inline Ring operator [] (int rank) const
    {
    	assert((rank >= 0) && (rank < lenght));
    	Ring ret;
    	ret.lenght = lenght;
    	ret.offset = rank * lenght;
    	return ret;
    }

    /*! \brief nextRow return the next row processor id, considering that the actual position in the torus are `row` and `col` */
    inline int nextRow(int row, int col) const{
		assert((row >= 0) && (row < lenght));
		assert((col >= 0) && (col < lenght));
        return (*this)[(row + 1) % lenght][col];
	}

    /*! \brief nextRow return the next col processor id, considering that the actual position in the torus are `row` and `col` */
	inline int nextCol(int row, int col) const{
		assert((row >= 0) && (row < lenght));
		assert((col >= 0) && (col < lenght));
        return (*this)[row].next(col);
	}

    /*! \brief nextRow return the previous row processor id, considering that the actual position in the torus are `row` and `col` */
    inline int previousRow(int row, int col) const{
		assert((row >= 0) && (row < lenght));
		assert((col >= 0) && (col < lenght));
        int mod = (row - 1) % lenght;
        return (*this)[((mod >= 0) ? mod : lenght + mod)][col];
	}

    /*! \brief nextRow return the previous col processor id, considering that the actual position in the torus are `row` and `col` */
    inline int previousCol(int row, int col) const{
		assert((row >= 0) && (row < lenght));
		assert((col >= 0) && (col < lenght));
        return (*this)[row].previous(col);
	}

    /*! \brief coord return a `Coord` object that contain the coordinate of the processor `id` in the torus */
    inline void coord(int id, Coord& ret) const{
		assert((id >= 0) && (id < lenght*lenght));
        ret.col = (id % lenght);
        ret.row = (id - ret.col) / lenght;
	}
};

#endif // TORUS_H
